#include <iostream>

#include <Network.h>
#include <Controller.h>
#include <XMLOutputMesoscopicInterface.h>

using namespace std;

void* run(void *v) {
	Controller* controler = (Controller*) v;

	try {
		controler->startSimulation();
	}catch(const char* ex) {
		cout << "Exception: " << ex;
	}
}

int main(int argc, char** argv) {

	try {
		Network network;

		network.addNode("N_0_0", 0,     0);
		network.addNode("N_1_0", 100,   0);
		network.addNode("N_2_0", 200,   0);
		network.addNode("N_3_0", 300,   0);
		network.addNode("N_2_1", 200, 200);
		network.addNode("N_0_1",   0, 200);
		network.addNode("N_1_1", 100, 200);
		network.addNode("N_3_1", 300, 200);
		network.addNode("N_1_2", 100, 300);
		network.addNode("N_2_2", 200, 300);
		network.addNode("N_3_2", 300, 300);
		network.addNode("N_0_2",   0, 300);

		//Add links
		network.addEdge("N_0_0", "N_1_0", 5);
		network.addEdge("N_1_0", "N_2_0", 5);
		network.addEdge("N_1_1", "N_1_0", 5);
		network.addEdge("N_1_1", "N_2_1", 5);
		network.addEdge("N_1_2", "N_1_1", 5);
		network.addEdge("N_0_1", "N_1_1", 5);
		network.addEdge("N_2_1", "N_3_1", 5);
		network.addEdge("N_2_1", "N_2_2", 5);
		network.addEdge("N_2_0", "N_2_1", 5);
		network.addEdge("N_2_0", "N_3_0", 5);
		network.addEdge("N_2_2", "N_1_2", 5);
		network.addEdge("N_3_2", "N_2_2", 5);
		network.addEdge("N_1_2", "N_0_2", 5);

		//Phases
		std::vector<std::string> links;
		std::vector<int> flush;

		//Center
		links.push_back("N_1_0");
		links.push_back("N_2_1");
		flush.push_back(1);
		flush.push_back(5);
		network.addPhase("N_1_1", "N_1_2", links, flush, 10);
		network.addPhase("N_1_1", "N_0_1", links, flush, 60);
		links.clear();
		flush.clear();

		//East
		links.push_back("N_3_1");
		links.push_back("N_2_2");
		flush.push_back(5);
		flush.push_back(5);
		network.addPhase("N_2_1", "N_2_0", links, flush, 10);
		network.addPhase("N_2_1", "N_1_1", links, flush, 60);
		links.clear();
		flush.clear();

		//N_1_0
		links.push_back("N_2_0");
		flush.push_back(5);
		network.addPhase("N_1_0", "N_1_1", links, flush, 30);
		network.addPhase("N_1_0", "N_0_0", links, flush, 30);
		links.clear();
		flush.clear();

		//N_2_0
		links.push_back("N_3_0");
		links.push_back("N_2_1");
		flush.push_back(5);
		flush.push_back(5);
		network.addPhase("N_2_0", "N_1_0", links, flush, 30);
		links.clear();
		flush.clear();

		//N_1_2
		links.push_back("N_1_1");
		links.push_back("N_0_2");
		flush.push_back(2);
		flush.push_back(5);
		network.addPhase("N_1_2", "N_2_2", links, flush, 30);
		links.clear();
		flush.clear();

		//N_2_2
		links.push_back("N_1_2");
		flush.push_back(5);
		network.addPhase("N_2_2", "N_3_2", links, flush, 10);
		network.addPhase("N_2_2", "N_2_1", links, flush, 10);
		links.clear();
		flush.clear();

		//Sources
		network.addSource("N_0_1", "N_1_1", 3);
		network.addSource("N_0_0", "N_1_0", 2);
		network.addSource("N_3_2", "N_2_2", 2);

		XMLOutputMesoscopicInterface output("mesoscopic.out.xml");
		Controller controller(&network);
		controller.setOutput((SimulatorOutput*)&output);

		pthread_t thread;
		pthread_attr_t attrs;
		pthread_attr_init(&attrs);
		pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_JOINABLE);
		pthread_create(&thread, &attrs, run, &controller);

		char c;
		std::cin >> c;
		controller.stopSimulation();

		pthread_join(thread, 0);
	}
	catch(const char* ex) {
		cout << "Exception: " << ex;
	}

	return 0;
}
